#include <iostream>
#include <vector>
#include "Thread.hpp"

using namespace ThreadModule;

#define NUM 4
int ticketnum = 10000; // 共享资源

// 	// 这份代码ticket会被减到负数，原因：
// 	// 1.if判断不是原子性操作  2. 多个线程进行调度切换执行
// 	// 线程什么时候会切换？ 1.时间片耗尽 2.更高优先级的进程调度--优先级抢占
// 	// 3. 通过sleep，然后从内核返回用户时，会进行时间片是否到达检测，进而导致切换

// void Ticket()
// {
// 	while(1)
// 	{
// 		if(ticketnum > 0)
// 		{
// 			//加usleep主动制造线程切换，让多线程竞争问题必现，不加usleep线程执行快，竞争问题被隐藏
// 			usleep(1000); // 加usleep会暴露问题

// 			// 1.抢票
// 			printf("get a new ticket,id:%d\n",ticketnum--);

// 			// 2.入库 (用休眠模拟)
// 			//usleep(1000);
// 		}
// 		else{
// 			break;
// 		}
// 	}
// }

// 解决方案：
// 1.所有对资源的保护，都是对临界区代码的保护，因为资源是通过代码访问的
// 2.加锁，一定不能大块代码进行加锁，要保证细粒度

// 锁本身也是全局的共享资源，谁保证锁的安全？加锁和解锁被设计成为原子的了
//pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; // 全局锁,可以不用销毁


class ThreadData
{
public:
	std::string name;
	pthread_mutex_t *lock_ptr;
};
void Ticket(ThreadData & td)
{
	while (1)
	{
		pthread_mutex_lock(td.lock_ptr);
		if (ticketnum > 0)
		{
			usleep(1000);
			// 1.抢票
			printf("ticket: %d,who get it: %s\n", ticketnum--,td.name.c_str());

			// 2.入库 (用休眠模拟)
			// usleep(1000);
			pthread_mutex_unlock(td.lock_ptr);
		}
		else
		{
			pthread_mutex_unlock(td.lock_ptr);
			break;
		}
	}
}

int main()
{
	// 局部的锁
	pthread_mutex_t lock;
	pthread_mutex_init(&lock,nullptr); // 属性默认nullptr


	// 1.构建线程对象
	std::vector<Thread<ThreadData>> threads;
	for (int i = 0; i < NUM; i++)
	{
		ThreadData *td = new ThreadData();
		td->lock_ptr = &lock;
		threads.emplace_back(Ticket,*td);
		td->name = threads.back().Name();
	}

	// 2.启动线程
	for (auto &thread : threads)
	{
		thread.Start();
	}

	for (auto &thread : threads)
	{
		thread.Join();
	}

	pthread_mutex_destroy(&lock); //局部锁需要销毁

	return 0;
}